using System.Reflection;
using Castle.DynamicProxy;
using KL.Standard.Model.Attribute;
using KL.Standard.Repositories.DBContext;
using Microsoft.Extensions.Logging;

namespace KL.Core.Extensions.AOP;

/// <summary>
/// 拦截器
/// </summary>
public class TransactionInterceptor : IInterceptor
{

    //public MutilInstanceFactory InstanceFactory { set; get; }

    private readonly ILogger<TransactionInterceptor> _log;

    private readonly MyDbContext _myDbContext;
    

    public TransactionInterceptor(ILogger<TransactionInterceptor> logger, MyDbContext myDbContext)
    {
        _log = logger;
        _myDbContext = myDbContext;
    }

    //public UnitOfWorkIInterceptor(_dbContext dBContext)
    //{
    //    this.dBContext = dBContext;
    //}
    public void Intercept(IInvocation invocation)
    {
        MethodInfo methodInfo = invocation.MethodInvocationTarget;
        if (methodInfo == null)
            methodInfo = invocation.Method;

        RepoUseTranAttribute unitOfWork = methodInfo.GetCustomAttributes<RepoUseTranAttribute>(true).FirstOrDefault();
        if (unitOfWork != null)
        {
            var tenantId = unitOfWork.DataSourceTag;
            if (string.IsNullOrEmpty(tenantId))
            {
                //_log.Error("获取_dbContext 失败，请检查数据源容器的设置");
                _myDbContext.RollBackTransaction(tenantId);
                throw new Exception("[RepoUseTran]在仓储层的标签必须配置{租户ID}标识！");
            }
            if (_myDbContext == null)
            {
                //_log.Error("获取_dbContext 失败，请检查数据源容器的设置");
                _myDbContext.RollBackTransaction(tenantId);
                throw new Exception("[TransactionInterceptor]获取_dbContext 失败，请检查数据源容器的设置");
            }

            //如果标记了 [RepoUseTran]，并且不在事务嵌套中。
            if (_myDbContext.Committed)
            {

                //开启事务
                _log.LogInformation($"[TransactionInterceptor] 开启事务:{_myDbContext.ID}");
                _myDbContext.BeginTransaction(tenantId);
                try
                {
                    //事务包裹 查询语句 
                    //https://github.com/mysql-net/MySqlConnector/issues/405
                    invocation.Proceed();
                    _log.LogInformation($"[CommitTransaction] 提交事务:{_myDbContext.ID}");
                    //提交事务
                    _myDbContext.CommitTransaction(tenantId);
                }
                catch (Exception ex)
                {
                    //回滚
                    _myDbContext.RollBackTransaction(tenantId);
                    _log.LogError($"[TransactionInterceptor] 执行异常，{ex.StackTrace}");
                    throw;
                }
            }
            else
            {
                //如果没有标记[UnitOfWork]，直接执行方法
                invocation.Proceed();
            }
        }
        else
        {
            //如果没有标记[UnitOfWork]，直接执行方法
            invocation.Proceed();
        }


    }
}